//#define __STDC_WANT_LIB_EXT1__ 1

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>


#define BUF_LEN 100													//Input buffer size
#define INIT_STR_EXT 50												//Initial space for prose
#define WORDS_INCR 5												//Words capacity increment


int main(void){

	char delimiters[] = " \n\".,;:!?()";								//Prose delimiters
	char buf[BUF_LEN];													//Buffer for a line of keyboard input
	size_t str_size = INIT_STR_EXT;										//Current memory to store prose
	char* pStr = malloc(str_size);										//Pointer to prose to be tokenized
	if(!pStr){
		printf("allocate memory for Pointer of prose failed\n");
		return 1;
	}

	*pStr = '\0';														//Set 1st charactor to null

	printf("Enter some prose with up to %d characters per line.\nTerminate input by entering an empty line:\n", BUF_LEN);

	while(true){
		fgets(buf,BUF_LEN,stdin);										//Read a line of input
		if(buf[0] == '\n')												//An empty line ends input
			break;

		// if(strnlen_r(pStr,str_size) + strnlen_r(buf,BUF_LEN) + 1 > str_size){
			// str_size = strnlen_r(pStr,str_size) + strnlen_r(buf,BUF_LEN) + 1;
		if(strnlen(pStr,str_size) + strnlen(buf,BUF_LEN) + 1 > str_size){
			str_size = strnlen(pStr,str_size) + strnlen(buf,BUF_LEN) + 1;
			pStr = realloc(pStr,str_size);
		}

		// if(strcat_r(pStr,str_size,buf)){								//Concatenate the line with pStr
		if(!strcat(pStr,buf)){											//Concatenate the line with pStr
			printf("Something's worng. String Concatenate failed.\n");
			return 1;
		}
	}


	//Find and list all the words in prose
	size_t maxWords = 10;												//Current maximum word count
	int word_count = 0;													//Current word count
	size_t word_length = 0;												//Current word length
	// char** pWords = callloc(maxWords,sizeof(char*));					//Stores pointers to the words
	char** pWords = malloc(maxWords*sizeof(char*));						//Stores pointers to the words
	
	if(!pWords){
		printf("allocate memory for Pointer of storing pointers to the words failed\n");
		return 1;
	}	
	// int* pnWord = callloc(maxWords,sizeof(int));						//Stores count for each word
	int* pnWord = malloc(maxWords*sizeof(int));							//Stores count for each word
	if(!pnWord){
		printf("allocate memory for Pointer of storing count for each word failed\n");
		return 1;
	}	

	// size_t str_len = strnlen_r(pStr,str_size);						//Length used by strtok_s()
	size_t str_len = strnlen(pStr,str_size);							//Length used by strtok_s()
	char* ptr = NULL;													//Pointer used by strtok_s()
	// char* pWord = strtok_s(pStr,&str_len,delimiters,&ptr);			//Find 1st word
	char* pWord = strtok_r(pStr,delimiters,&ptr);						//Find 1st word

	if(!pWord){
		printf("No words found. Ending program.\n");
		return 1;
	}

	bool new_word = true;												//False for an existing word
	while(pWord){
		//check for existing word
		for(int i=0;i<word_count;i++){
			if(strcmp(*(pWords+i),pWord)==0){
				++*(pnWord+i);
				new_word = false;
				break;
			}
		}
		if(new_word){													//Check for new word
			//Check for sufficent memory
			if(word_count == maxWords){										
				maxWords += WORDS_INCR;
				pWords = realloc(pWords,maxWords*sizeof(char*));		//Get more space for pointers to words


																			
				pnWord = realloc(pnWord,maxWords*sizeof(int));			//Get more space for word counts
			}
			//Found a new word so get memory for it and copy it here
			word_length = ptr-pWord;									//Length of new word
			*(pWords + word_count) = malloc(word_length);				//Allocate memory for word
			// strcpy_r(*(pWords + word_count),word_length,pWord);		//Copy to array
			strcpy(*(pWords + word_count),pWord);						//Copy to array
			*(pnWord + word_count ++) = 1;								//Set new word count
		}else
			new_word = true;											//Reset new word flag


		// pWord = strtok_s(NULL, &str_len, delimiters, &ptr);			//Find subsequent word
		pWord = strtok_r(NULL, delimiters, &ptr);						//Find subsequent word

	}


	//Output the words and counts
	for(int i=0;i<word_count;i++){
		printf(" %-13s %3d",*(pWords+i),*(pnWord+i) );
		if((i+1) % 4 ==0)
			printf("\n");
	}


	printf("\n");

	//Free the memory for words
	for (int i = 0; i < word_count; ++i)
	{
		free(*(pWords+i));												//Free memory for word
		*(pWords+i) = NULL;												//Reset the pointer
	}

	free(pWords);														//Free memory for pointers to words
	pWords = NULL;															

	free(pnWord);														//Free memory for word counts
	pnWord = NULL;

	free(pStr);
	pStr = NULL;														//Free memory for prose

	return 0;


}
